home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
ARASAN_S.ZIP
/
MOVEGEN.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-12
|
9KB
|
290 lines
// Copyright 1994 by Jon Dart. All Rights Reserved.
#include "movegen.h"
#include "bearing.h"
#include "emove.h"
#include "rmove.h"
#include "scoring.h"
#include "moveord.h"
#include "util.h"
#include <iostream.h>
#ifdef RANGE_CHECK
#include <assert.h>
#endif
Move_Generator::Move_Generator(const Board & ABoard,
const unsigned ply, const Move & last_move):
board(ABoard), my_ply(ply), my_last_move(last_move)
{
}
Move_Generator::~Move_Generator()
{
}
inline void Move_Generator::
SetMove(const Square source, const Square dest,
const Piece::PieceType promotion, Move * moves, unsigned &NumMoves)
{
#ifdef RANGE_CHECK
assert(source.OnBoard());
assert(dest.OnBoard());
assert(NumMoves <= Move_Generator::MaxMoves);
#endif
moves[NumMoves] = Move(source, dest, promotion);
++NumMoves;
}
int Move_Generator::
Generate_Moves(Move * moves, const Boolean captures_only,
const Boolean repeatable)
{
unsigned NumMoves;
if (board.CheckStatus() == Board::InCheck)
{
NumMoves = Check_Evasions(moves);
}
else
{
NumMoves = 0;
// castling moves
if (!captures_only)
{
const ColorType side = board.Side();
Board::CastleType CS = board.CastleStatus(side);
if ((CS == Board::CanCastleEitherSide) ||
(CS == Board::CanCastleKSide))
{
const Square kp = board.KingPos(side);
if (board[kp + 1].IsEmpty() &&
board[kp + 2].IsEmpty() &&
board.num_attacks(kp,OppositeColor(side)) == 0 &&
board.num_attacks(kp + 1,OppositeColor(side)) == 0 &&
board.num_attacks(kp + 2,OppositeColor(side)) == 0)
// can castle
SetMove(kp, kp + 2,
Piece::Invalid,
moves, NumMoves);
}
if ((CS == Board::CanCastleEitherSide) ||
(CS == Board::CanCastleQSide))
{
const Square kp = board.KingPos(side);
if (board[kp - 1].IsEmpty() &&
board[kp - 2].IsEmpty() &&
board[kp - 3].IsEmpty() &&
board.num_attacks(kp,OppositeColor(side)) == 0 &&
board.num_attacks(kp - 1,OppositeColor(side)) == 0 &&
board.num_attacks(kp - 2,OppositeColor(side)) == 0)
// can castle
SetMove(kp, kp - 2,
Piece::Invalid,
moves, NumMoves);
}
}
// other moves
static Square squares[Bearing::MaxBearSq];
for (int i = 0; i < 16; i++)
{
Square loc = board.PiecePos(board.Side(), i);
if (!loc.IsInvalid())
{
int n = Bearing::BearSq(board, loc, squares);
const Piece piecemoved = board[loc];
for (int j = 0; j < n; j++)
{
const Square dest(squares[j]);
int promotion =
piecemoved.Type() == Piece::Pawn &&
dest.Rank(board.Side()) == 8;
if (promotion)
{
SetMove(loc, dest, Piece::Queen, moves, NumMoves);
SetMove(loc, dest, Piece::Rook, moves, NumMoves);
SetMove(loc, dest, Piece::Bishop, moves, NumMoves);
SetMove(loc, dest, Piece::Knight, moves, NumMoves);
}
else if (captures_only)
{
if (!board[dest].IsEmpty() ||
((piecemoved.Type() == Piece::Pawn) &&
(dest.File() != loc.File())))
SetMove(loc, dest, Piece::Invalid, moves, NumMoves);
}
else
SetMove(loc, dest, Piece::Invalid, moves, NumMoves);
}
}
}
}
if (repeatable)
{
int *scores = new int[NumMoves];
for (int i = 0; i < NumMoves; i++)
{
scores[i] = moves[i].StartSquare() & (moves[i].DestSquare() << 7);
switch (moves[i].PromoteTo())
{
case Piece::Queen:
scores[i] &= 0xB000;
break;
case Piece::Rook:
scores[i] &= 0x8000;
break;
case Piece::Bishop:
scores[i] &= 0x4000;
break;
default:
break;
}
}
Move_Ordering::sort_moves(moves, scores, NumMoves);
delete[] scores;
}
return NumMoves;
}
static Boolean is_pinned(const Board & board, const Square source,
const Square dest)
{
Boolean pin = False;
if (board.num_attacks(source, board.OppositeSide()) > 0)
{
// It is possible that the piece we plan to move is pinned.
Piece PinnedByPiece;
Square PinnedBySquare;
int dir;
if (Bearing::Pinned(board, source, PinnedByPiece,
PinnedBySquare, dir))
{
// This code checks for moves in the direction of the pin,
// which are ok:
int dir1 = Util::Abs((int) source - (int) dest);
int dir2 = Util::Abs(dir);
if (dir2 == 1 && source.Rank() != dest.Rank())
pin = True;
else if (dir2 == RankIncr && source.File() != dest.File())
pin = True;
else if (dir1 % dir2)
pin = True;
}
}
return pin;
}
unsigned Move_Generator::Check_Evasions(Move * moves)
{
int num_moves = 0;
unsigned n;
unsigned i;
static Square squares[36];
Square source;
const Square kp = board.KingPos(board.Side());
unsigned num_attacks = board.num_attacks(kp, board.OppositeSide());
const int double_check = num_attacks > 1;
if (!double_check)
{
// try to capture checking piece
unsigned n = Bearing::Attack(board, kp, board.OppositeSide(), squares);
assert(n);
source = squares[0];
#ifdef RANGE_CHECK
assert(!board[source].IsEmpty() && board[source].Type() != Piece::King);
#endif
n = Bearing::Attack(board, source, board.Side(), squares);
for (i = 0; i < n; i++)
{
if (board[squares[i]].Type() == Piece::King)
{
// We can capture with the king only if the piece
// checking us is undefended.
if (board.num_attacks(source, board.OppositeSide()) == 0)
moves[num_moves++] = Move(squares[i], source);
}
else
{
if (!is_pinned(board, squares[i], source))
moves[num_moves++] = Move(squares[i], source);
}
}
// Bearing::Attack does not return en passant captures, so try
// this as a special case
if (board.EnPassantSq(board.OppositeSide()) == source)
{
Square dest(source + RankIncr * Direction[board.Side()]);
Piece myPawn(Piece::Pawn,board.Side());
if (source.File() != 8 && board[source + 1] == myPawn)
{
Piece tmp(board[source]);
Piece &place = (Piece &)board[source];
place = Piece::EmptyPiece(); // imagine me gone
if (!is_pinned(board, source + 1, dest))
moves[num_moves++] = Move(source + 1, dest);
place = tmp;
}
if (source.File() != 1 && board[source - 1] == myPawn)
{
Piece tmp(board[source]);
Piece &place = (Piece &)board[source];
place = Piece::EmptyPiece(); // imagine me gone
if (!is_pinned(board, source - 1, dest))
moves[num_moves++] = Move(source - 1, dest);
place = tmp;
}
}
// try to interpose a piece
if (board[source].Type() != Piece::Knight &&
board[source].Type() != Piece::Pawn)
{
Square btwn_squares[8];
unsigned nbsq = board.Between(source, kp, btwn_squares);
for (i = 0; i < nbsq; i++)
{
n = Bearing::Attack(board, btwn_squares[i],
board.Side(), squares);
for (unsigned j = 0; j < n; j++)
{
if (board[squares[j]].Type() != Piece::King &&
!is_pinned(board, squares[j], btwn_squares[i]))
moves[num_moves++] = Move(squares[j], btwn_squares[i]);
}
}
}
}
// generate evasive moves
n = Bearing::BearSq(board, kp, squares);
Square atck_squares[8];
unsigned num_attackers = Bearing::Attack(board, kp,
board.OppositeSide(), atck_squares);
for (i = 0; i < n; i++)
{
if (board.num_attacks(squares[i], board.OppositeSide()) == 0)
if (double_check || squares[i] != source)
{
// We need to do some extra checking, since the board
// info on attacks reflects the state before the move,
// and we need to be sure that the destination square
// is not attacked after the move.
Boolean illegal = False;
for (int j = 0; j < num_attackers && !illegal; j++)
{
Piece attacker(board[atck_squares[j]]);
if (attacker.sliding())
{
int dir = board.Direction(atck_squares[j], squares[i]);
// check for movement in the direction of the
// attacker:
if (dir != 0 && (kp + dir == squares[i]))
illegal = True;
}
}
if (!illegal)
moves[num_moves++] = Move(kp, squares[i]);
}
}
return num_moves;
}